﻿// -----------------------------------------------------------------------
// <copyright file="Parser.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace ParserTree
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class Parser
    {
        Scanner.Token currentToken;
        
        
        public TreeNode parse(Scanner.Scanner newScanner)
        {
            this.myScanner = newScanner;
            currentToken = newScanner.GetNextToken();
            bool result ;
            TreeNode Node = new TreeNode();
                Node= this.Start();
                Node.convert();
            if (currentToken.TokenType == Scanner.TokenType.EndFile )
            {
                return Node;
            }
            else
            {
                return null;
            }
        }
        public TreeNode Start()
        {
            TreeNode Node = new TreeNode();
            Node.Type = TreeNode.NodeType.program;
            Node.left= this.StmtSequence();
            Node.convert();
            return Node;
        }
        private TreeNode StmtSequence()
        {
            TreeNode Node = new TreeNode();
            Node.Type = TreeNode.NodeType.statmSeq;
            bool result = false;
            Node.left = this.Statement();
            if (currentToken.TokenType == Scanner.TokenType.SemiColon)
            {
                result = this.Match(Scanner.TokenType.SemiColon);
                if (result == true)
                {
                    Node.right = this.StmtSequence();
                }
                //while (currentToken.TokenType == Scanner.TokenType.SemiColon)
                //{
                //    result = this.Match(Scanner.TokenType.SemiColon);
                //    if (result == true)
                //    {
                //        Node.right = this.Statement();
                //    }
                //    else
                //        break;
                //}
            }
            else
            {
                Node.convert();
                return Node;
            }
            Node.convert();
            return Node;
        }
        private TreeNode Statement()
        {
            TreeNode Node = new TreeNode();
            Node.Type = TreeNode.NodeType.Statment;
            Node.convert();
            if (currentToken.TokenType == Scanner.TokenType.Write)
            {
                return this.WriteStmt();
            }
            else if (currentToken.TokenType == Scanner.TokenType.Read)
            {
                return this.ReadStmt();
            }
            else if (currentToken.TokenType == Scanner.TokenType.Repeat)
            {
                return this.RepeatStmt();
            }
            else if (currentToken.TokenType == Scanner.TokenType.If)
            {
                return this.IfStmt();
            }
            else if (currentToken.TokenType == Scanner.TokenType.ID)
            {
                return this.AssignStmt();
            }
            else
            {
                return null;
            }
        }
        private TreeNode AssignStmt()
        {
            TreeNode Node = new TreeNode();
            Node.Type = TreeNode.NodeType.assignNode;
            Node.Value = this.currentToken.Lexem;
            bool result = this.Match(Scanner.TokenType.ID);
            if (result == true)
            {
                result = this.Match(Scanner.TokenType.Assign);
                if (result == true)
                {
                    Node.left = this.Experation();
                }
            }
            Node.convert();
            return Node;
        }
        private TreeNode IfStmt()
        {
            TreeNode Node = new TreeNode();
            Node.Type = TreeNode.NodeType.ifNode;
            bool result = this.Match(Scanner.TokenType.If);
            if (result == true)
            {
                Node.left = this.Experation();
                if (result == true)
                {
                    result = this.Match(Scanner.TokenType.Then);
                    if (result == true)
                    {
                        Node.middel = this.StmtSequence();
                        switch (this.currentToken.TokenType)
                        {
                            case Scanner.TokenType.End:
                                {
                                    result = this.Match(Scanner.TokenType.End);
                                }
                                break;
                            case Scanner.TokenType.Else:
                                {
                                    result = this.Match(Scanner.TokenType.Else);
                                    if (result == true)
                                    {
                                        Node.right = this.StmtSequence();
                                        if (result == true)
                                        {
                                            result = this.Match(Scanner.TokenType.End);
                                        }
                                    }
                                }
                                break;
                            default:
                                {
                                    //return this.Reject();
                                }
                                break;
                        }
                        Node.convert();
                        return Node;
                    }
                }
            }
            Node.convert();
            return Node;
        }
        private TreeNode RepeatStmt()
        {
            TreeNode Node = new TreeNode();
            Node.Type = TreeNode.NodeType.repeatNode;

            bool result = this.Match(Scanner.TokenType.Repeat);
            if (result == true)
            {
                Node.left = this.StmtSequence();
                if (result == true)
                {
                    result = this.Match(Scanner.TokenType.Until);
                    if (result == true)
                    {
                        Node.right = this.Experation();
                    }
                }
            }
            Node.convert();
            return Node;
        }
        private TreeNode ReadStmt()
        {
            TreeNode Node = new TreeNode();
            Node.Type = TreeNode.NodeType.readNode;
            
            bool result = this.Match(Scanner.TokenType.Read);
            if (result == true)
            {
                Node.Value = this.currentToken.Lexem;
                result = this.Match(Scanner.TokenType.ID);
            }
            Node.convert();
            return Node;
        }
        private TreeNode WriteStmt()
        {
            TreeNode Node = new TreeNode();
            Node.Type = TreeNode.NodeType.writeNode;
            
            bool result = this.Match(Scanner.TokenType.Write);
            if (result == true)
            {
                Node.left = this.Experation();
            }
            Node.convert();
            return Node;
        }
        public TreeNode Experation()
        {
            TreeNode Node = new TreeNode();
            Node.Type = TreeNode.NodeType.Exp;
            Node.left = this.SimpleExp();
            while ( (currentToken.TokenType == Scanner.TokenType.Equal || currentToken.TokenType == Scanner.TokenType.LessThan))
            {
                //bool result ;//= this.ComparisonOper();
                Node.middel = new TreeNode();
                Node.middel = this.ComparisonOper();
                //if (result == true)
                {
                    Node.right = new TreeNode();
                    Node.right = this.SimpleExp();
                }
            }
            Node.convert();
            return Node;
        }
        private TreeNode ComparisonOper()
        {
            bool result;
            TreeNode Node = new TreeNode();
            Node.Type = TreeNode.NodeType.comparisonNode;

            if (currentToken.TokenType == Scanner.TokenType.LessThan)
            {
                result = this.Match(Scanner.TokenType.LessThan);
                Node.Value = "<";
            }
            else if (currentToken.TokenType == Scanner.TokenType.Equal)
            {
                result = this.Match(Scanner.TokenType.Equal);
                Node.Value = "=";
            }
            else
            {
                //return Reject();
            }
            Node.convert();
            return Node;
        }
        private TreeNode SimpleExp()
        {
            bool result;//= this.Term();
            TreeNode Node = new TreeNode();
            Node.Type = TreeNode.NodeType.simpleExp;
              Node.left  = this.Term();

              if (currentToken.TokenType == Scanner.TokenType.Plus || currentToken.TokenType == Scanner.TokenType.Minus)
              {
                  Node.middel = this.AddOper();
                  Node.right = SimpleExp();
              }
              else
              {
                  Node.convert();
                  return Node;
              }
            //while ( (currentToken.TokenType == Scanner.TokenType.Plus || currentToken.TokenType == Scanner.TokenType.Minus))
            //{
            //    //Node.middel = this.AddOper();
            //    ////if (result == true)
            //    //{
            //    //    Node.right = this.Term();
            //    //}
                
            //}
            Node.convert();
            return Node;
        }
        private TreeNode AddOper()
        {
            bool result;
            TreeNode Node = new TreeNode();
            Node.Type = TreeNode.NodeType.operationNode;
            
            if (this.currentToken.TokenType == Scanner.TokenType.Minus)
            {
                result = this.Match(Scanner.TokenType.Minus);
                Node.Value = "-";
            }
            else if (this.currentToken.TokenType == Scanner.TokenType.Plus)
            {
                result = this.Match(Scanner.TokenType.Plus);
                Node.Value = "+";
            }
            else
            {
                //return Reject();
            }
            Node.convert();
            return Node;
        }
        public TreeNode Term()
        {
            //bool result = this.Factor();
            TreeNode Node = new TreeNode();
            Node.Type = TreeNode.NodeType.term;
            Node.left = this.Factor();
            if (currentToken.TokenType == Scanner.TokenType.Times)
            {
                Node.middel = new TreeNode();
                Node.middel.Type = TreeNode.NodeType.MulOpNode;
                Node.middel.Value = "*";
                Node.middel.convert();
            }
            
            while ( currentToken.TokenType == Scanner.TokenType.Times)
            {
                bool result = Match(Scanner.TokenType.Times);
                if (result == true)
                {
                    Node.right = this.Term();
                }
            }
            Node.convert();
            return Node;

        }
        private TreeNode Factor()
        {
            bool result;
            TreeNode Node = new TreeNode();
            Node.Type = TreeNode.NodeType.factor;
            switch (currentToken.TokenType)
            {
                case Scanner.TokenType.LeftParentheses:
                    {
                        result = this.Match(Scanner.TokenType.LeftParentheses);
                        if (result == true)
                        {
                            Node.left = new TreeNode();   
                            Node.left = this.Experation();
                            if (result == true)
                            {
                                result = this.Match(Scanner.TokenType.RightParentheses);
                            }
                        }
                    }
                    break;
                case Scanner.TokenType.Num:
                    {
                        Node.left = new TreeNode();
                        Node.left.Value = this.currentToken.Lexem;
                        Node.left.Type = TreeNode.NodeType.num;
                        Node.left.convert();
                        result = this.Match(Scanner.TokenType.Num);                      
                    }
                    break;
                case Scanner.TokenType.ID:
                    {
                        
                        Node.left = new TreeNode();
                        Node.left.Type = TreeNode.NodeType.identefier;
                        Node.left.Value = this.currentToken.Lexem;
                        Node.left.convert();
                        result = this.Match(Scanner.TokenType.ID);
                    }
                    break;
                default:
                    {
                       // Node = new TreeNode();
                    }
                    break;
            }
            Node.convert();
            return Node;
        }
        public bool Match(Scanner.TokenType s)
        {
            if (currentToken.TokenType == s)
            {
                this.currentToken = this.myScanner.GetNextToken();
                return this.Accept();
            }
            else
            {
                return this.Reject();
            }
        }
        private bool Accept()
        {
            return true;
        }
        private bool Reject()
        {
            return false;
        }
        public Scanner.Scanner myScanner { get; set; }
    }
}
